#include "evm_module.h"
#include <windows.h>
#include <pthread.h>
#include <tchar.h>
#include "pthread.h"

#include "evmlist.h"

typedef struct uart_struct {
    HANDLE hd;
    int id;
    pthread_t fd;
    void *msg;
}uart_struct_t;

static list_t *uartlist = NULL;

static HANDLE getComByID(int id){
    int len = list_len(uartlist);
    for(int i=0; i<len; i++){
        uart_struct_t *uart ;
        if(list_get(uartlist, i, &uart)){
            if(uart->id == id)
                return uart->hd;
        }
    }
    return (HANDLE)-1;
}

static pthread_t getThreadByID(int id){
    int len = list_len(uartlist);
    for(int i=0; i<len; i++){
        uart_struct_t *uart ;
        if(list_get(uartlist, i, &uart)){
            if(uart->id == id)
                return uart->fd;
        }
    }
    return -1;
}

static void* getObjByID(int id){
    int len = list_len(uartlist);
    for(int i=0; i<len; i++){
        uart_struct_t *uart ;
        if(list_get(uartlist, i, &uart)){
            if(uart->id == id)
                return uart;
        }
    }
    return NULL;
}

static int getIndexByID(int id){
    int len = list_len(uartlist);
    for(int i=0; i<len; i++){
        uart_struct_t *uart ;
        if(list_get(uartlist, i, &uart)){
            if(uart->id == id)
                return i;
        }
    }
    return -1;
}

int evm_adaptor_uart_open(int id, int baud, int databits, int stopbits, int parity, int buffersize){
    evm_print("evm_adaptor_uart_open id:%d baud:%d databits:%d stopbits:%d parity:%d\r\n", id, baud, databits, stopbits, parity);

    char name[20] = {0};
    if(id<9)
        wsprintf(name, L"COM%d", id);
    else
        wsprintf(name, L"\\\\.\\COM%d", id);
    HANDLE hCom=CreateFile(name,                    //COM口
                        GENERIC_READ|GENERIC_WRITE, //允许读和写
                        0,                          //独占方式
                        NULL,
                        OPEN_EXISTING,              //打开而不是创建
                        0,                          //同步方式
                        NULL);

    if(hCom == (HANDLE)-1)
    {
        DWORD dwError = GetLastError();
        evm_print("打开COM失败! errcode:%d\r\n", dwError);
        return -1;
    }

    SetupComm(hCom,10240,10240); //输入缓冲区和输出缓冲区的大小都是1024
    COMMTIMEOUTS TimeOuts;
    //设定读超时
    TimeOuts.ReadIntervalTimeout = 100;
    TimeOuts.ReadTotalTimeoutMultiplier = 100;
    TimeOuts.ReadTotalTimeoutConstant=200;
    //设定写超时
    TimeOuts.WriteTotalTimeoutMultiplier=50;
    TimeOuts.WriteTotalTimeoutConstant=100;
    SetCommTimeouts(hCom,&TimeOuts); //设置超时

    DCB dcb;
    GetCommState(hCom,&dcb);
    dcb.BaudRate=   baud;
    dcb.ByteSize=   databits;
    dcb.Parity  =   parity;
    dcb.StopBits=   stopbits;
    SetCommState(hCom,&dcb);
    PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

    uart_struct_t *uartdata = evm_malloc(sizeof(uart_struct_t));
    if(uartdata == NULL)
        return -1;
    uartdata->id = id;
    uartdata->hd = hCom;
    uartdata->fd = -1;
    list_append(uartlist, uartdata);
    return 0;
}

int evm_adaptor_uart_write(int id, char *data, int len){
    HANDLE hCom = getComByID(id);
    if(hCom == (HANDLE)-1)
        return -1;

    DWORD dwBytesWrite = len;
    COMSTAT ComStat;
    DWORD dwErrorFlags;
    BOOL bWriteStat;
    ClearCommError(hCom,&dwErrorFlags,&ComStat);
    bWriteStat = WriteFile(hCom,data,dwBytesWrite,&dwBytesWrite,NULL);
    if(!bWriteStat){
        return -1;
    }

    if(dwBytesWrite != len)
        return -1;

    return 0;
}

int evm_adaptor_uart_read(int id, char *data, int len, int timeout){
    for(int i=0;i<len;i++)
        data[i] = i;
    evm_print("evm_module_uart_read id:%d len:%d\r\n", id, len);

    HANDLE hCom = getComByID(id);
    if(hCom == (HANDLE)-1)
        return -1;

    DWORD wCount;//读取的字节数
    BOOL bReadStat;
    bReadStat=ReadFile(hCom, data, len, &wCount,NULL);
    if(!bReadStat)
    {
        evm_print("读串口失败!\r\n");
        return -1;
    }
    return wCount;
}

//static c_struct_signature my_struct_descr[] = {
//  {"data", offsetof(msg_buffer_t, data), 'B', NULL},
//  {"len", offsetof(msg_buffer_t, len), 'i', NULL},
//  {NULL, 0, 0, NULL},
//};

//extern evm_val_t evm_struct_2_list(evm_t *e, evm_val_t *p, int argc, evm_val_t *v);
//evm_val_t uart_msg_hander(evm_t * e,void *msg) {
//    msg_buffer_t *msgbuff = (msg_buffer_t *)msg;

//    evm_val_t args[2];
//    args[0] = evm_mk_invoke(msg);
//    my_struct_descr[0].arg = msgbuff->len;
//    args[1] = evm_mk_invoke(my_struct_descr);

//    return evm_struct_2_list(e, &(e->root), 2, args);
//}

//void uart_msg_free(void *msg) {
//    if(msg == NULL)
//        return;
//    msg_buffer_t *msgbuff = (msg_buffer_t *)msg;
//    evm_free(msgbuff->data);
//    evm_free(msgbuff);
//}

static void *callback(void *args)
{
    uart_struct_t *uart = (uart_struct_t *)args;
    evm_event_msg_t *msg = uart->msg;

    HANDLE hCom = getComByID(uart->id);
    if(hCom == (HANDLE)-1)
        return NULL;

    char data[1024];
    DWORD wCount;//读取的字节数
    BOOL bReadStat;
    while(1){
        bReadStat=ReadFile(hCom, data, 1024, &wCount,NULL);
        if(bReadStat && wCount>0 ){
            evm_event_msg_t *msgbuff = evm_module_msg_create();
            if(msgbuff == NULL)
                break;
            memcpy(msgbuff, msg, sizeof(evm_event_msg_t));

            msg_buffer_t *msgdata = evm_malloc(sizeof (msg_buffer_t));
            msgdata->data = evm_malloc(wCount);
            if(msgdata->data == NULL)
                break;
            msgdata->len = wCount;
            memcpy(msgdata->data, data, wCount);

            msgbuff->data = msgdata;
            evm_module_msg_put(msgbuff, 1);
//            evm_free(msgbuff);
            continue;
        }
        if(!bReadStat)
        {
            usleep(5000);
        }
    }
    pthread_exit(NULL);
}


int evm_adaptor_uart_on(int id, void *param){
    evm_print("evm_adaptor_uart_on id:%d\r\n", id);

    uart_struct_t *uart = (uart_struct_t *)getObjByID(id);
    if(uart->fd != (pthread_t)-1){
        pthread_cancel(uart->fd);
        uart->fd = -1;
    }
    uart->msg = param;

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,  PTHREAD_CREATE_DETACHED);
    if ((pthread_create(&uart->fd, &attr, callback, uart)) == -1)
    {
        printf("create error!\n");
        return -1;
    }
    return 0;
}


int evm_adaptor_uart_close(int id){
    evm_print("evm_module_uart_close id:%d\r\n", id);
    HANDLE hCom = getComByID(id);
    if(hCom == (HANDLE)-1)
        return 0;
    CloseHandle(hCom);

    pthread_t hd = getThreadByID(id);
    if(hd != (pthread_t)-1){
        pthread_cancel(hd);
    }

    uart_struct_t *uart = (uart_struct_t *)getObjByID(id);
    if(uart!= NULL){
        evm_module_msg_clear(uart->msg);
        evm_free(uart->msg);
        evm_free(uart);
    }

    int index = getIndexByID(id);
    if(index != -1){
        list_pop(uartlist, index);
    }
    return 0;
}

int evm_adaptor_uart_init(void){
    if(uartlist != NULL)
        evm_free(uartlist);
    uartlist = evm_malloc(sizeof (list_t));
    if(uartlist == NULL)
        return -1;
    list_init(uartlist);
    return 0;
}

void evm_adaptor_uart_destory(void){
    if(uartlist == NULL)
        return;
    int len = list_len(uartlist);
    uart_struct_t *uart;
    for(int i=len; i>=0; i--){
        if(list_get(uartlist, i, &uart)){
            int id = uart->id;
            evm_adaptor_uart_close(id);
        }
    }
    evm_free(uartlist);
}

static evm_uart_t *s_dev_uart = NULL;
static bool s_uart_flag = false;
evm_uart_t *evm_module_uart_getInstance(void){
    return s_dev_uart;
}

/**
 * @brief  evm_module_uart_init
 * @note   UART模块初始化
 * @retval = 0 成功
 *         < 0 失败
 */
int evm_module_uart_init(void){
    if(s_uart_flag)
        return 0;

    s_dev_uart = evm_malloc(sizeof (evm_uart_t));
    if(s_dev_uart == NULL)
        return -1;

    s_dev_uart->open = evm_adaptor_uart_open;
    s_dev_uart->read = evm_adaptor_uart_read;
    s_dev_uart->write = evm_adaptor_uart_write;
    s_dev_uart->on = evm_adaptor_uart_on;
    s_dev_uart->close = evm_adaptor_uart_close;

    s_uart_flag = true;

    evm_adaptor_uart_init();
    return 0;
}

/**
 * @brief  evm_module_uart_destory
 * @note   UART模块销毁
 * @retval None
 */
void evm_module_uart_destory(void){
    evm_adaptor_uart_destory();
    s_uart_flag = false;
    if(s_dev_uart != NULL)
        evm_free(s_dev_uart);
    s_dev_uart = NULL;
}
